﻿//#define _CRT_SECURE_NO_WARNINGS
//#include <stdio.h>
//#include <math.h>

#include "common.h"

// 自定义函数 -> 计算平方根
double square_root(double x)
{
    double guess = x / 2.0;
    double diff = guess * guess - x;
    while (diff > 0.00001) // 误差小于 0.00001(可根据需要调整) 时退出循环
    {
        guess = (guess + x / guess) / 2.0; // 牛顿迭代法
        diff = guess * guess - x; // 更新误差
    }
    // 也可以使用库函数 sqrt() 计算平方根，头文件为 math.h
    // double guess = sqrt(x);
    // return guess;
    return guess;
}

// 交换两个变量的值
void swap(float* a, float* b)
{ // 必须是指针（传递地址）才能修改变量的值
    // 不能直接使用 a = b; b = a;
    // 因为形参是值传递(临时拷贝)，有自己的地址，不能修改原变量的值
    printf("Before swap: a = %.2f, b = %.2f\n", *a, *b);
    int temp = *a;
    *a = *b;
    *b = temp;
    printf("After swap: a = %.2f, b = %.2f\n", *a, *b);
}

//函数的参数可以是任意类型，包括基本数据类型（常量、变量、函数）、
//枚举类型（常量）、结构体、指针、数组等。
//函数只有调用的时候才分陪内存，调用完毕内存自动释放。（作用域）
//形参实例化之后相当于实参的副本（临时拷贝），修改形参的值不会影响实参的值。

int prime_number(int num)
{ // 判断一个自然数是否为素数
    if (num <= 1) // 1不是素数
        return 0;
    int i;
    for (i = 2; i <= num / 2; ++i) // 遍历所有可能的因子
        if (num % i == 0) // 找到因子
        {
            //printf("%d is not a prime number.\n", num);
            return 0; // 不是素数
        }
    return 1; // 是素数
}

//int count_numbers(int start, int end)
//{ // 计算从 start 到 end 之间的数字个数
//    int count = 0;
//    for (int i = start; i <= end; ++i)
//        ++count;
//    return count;
//}

int* prime_numbers(int start, int end)
{ // 计算从 start 到 end 之间的素数个数
    int count = 0;
    int max_size; // 计算素数个数
    int i;
    //#define MAX_SIZE end - start + 1; // 计算素数个数
    static int prime[500]; // 定义静态数组，节省内存
    for (i = start; i <= end; ++i)
        if (prime_number(i)) // 判断i是否为素数
        {
            printf("%d ", i); // 输出素数
            prime[count] = i; // 记录素数
            ++count; // 若是素数，则计数器加1
        }
    printf("\n");
    if (count == 0) // 没有素数
        printf("There is no prime number in the range [%d, %d].\n",
            start, end);
    //return count;
    return prime; // 返回素数数组
}

int is_leap_year(int year)
{
    if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0))
        // 能被4整除但不能被100整除的年份为闰年
        return 1;
    else
        // 其他年份为平年
        return 0;
}

int leap_years(int start, int end)
{
    // 计算从 start 到 end 之间的闰年个数
    int count = 0;
    for (int i = start; i <= end; ++i)
        if (is_leap_year(i))
        {
            printf("%d ", i); // 输出闰年
            ++count; // 若是闰年，则计数器加1
        }
    printf("\n");
    return count;
}

int binary_search(int* arr,
    // 数组首地址（建议写法），写为 int arr[] 也是指针，一样，不推荐（存在歧义）
    int left, int right, int key)
{
    // 二分查找算法
    // 不要在函数内部计算一个数组的长度（因为是指针），而应该传递数组的左右边界
    // 错误示例
    // int len = sizeof(arr) / sizeof(arr[0]); // 计算的数组长度永远为1
    while (left <= right)
    {
        int mid = (right - left) / 2 + left;
        if (arr[mid] == key)
        {
            printf("Found %d at index %d.\n", key, mid);
            return mid; // 找到元素，返回下标
        }
        else if (arr[mid] < key)
            left = mid + 1;
        else
            right = mid - 1;
    }
    printf("%d is not found in the array at index %d to %d.\n",
        key, left, right);
    return -1; // 未找到元素，返回-1
}

int add_add_num(int* num)
{
    // 实现每次调用函数都会增加一个变量的值
    //int temp = *num; // 保存原值
    return ++(*num); // 返回新值。这里不能是 ++num 或者 num++ 或者 *num++
    // 因为 num 是一个指针，自增运算符会使指针指向下一个地址，而非增加值。
    // *num++ 等价于 (*num)++，先取值再自增。
}

// 以下是 FittenCode 生成的小数转分数函数
// 定义分数结构体
typedef struct
{
    int numerator;   // 分子
    int denominator; // 分母
} Fraction;

// 计算最大公约数（GCD）
int gcd(int a, int b)
{
    if (b == 0)
        return a;
    return gcd(b, a % b);
}

// 小数转换为分数
Fraction decimal_to_fraction(double decimal)
{
    Fraction frac;
    int sign = decimal < 0 ? -1 : 1; // 记录符号
    decimal = (decimal < 0) ? -decimal : decimal; // 取绝对值

    // 将小数转换为分数
    // 假设精度为1000000（可以调整此值以改变精度）
    int precision = 1000000;
    int denominator = precision;
    int numerator = (int)(decimal * precision);

    // 约分
    int divisor = gcd(numerator, denominator);
    frac.numerator = sign * (numerator / divisor);
    frac.denominator = denominator / divisor;

    return frac;
}

int test_decimal_to_fraction(double decimal)
{
    // 小数转分数
    //double decimal = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
    Fraction frac = decimal_to_fraction(decimal);
    printf("小数 %.20lf 转化为分数：%d/%d\n",
        decimal, frac.numerator, frac.denominator);
}